import json

from django.db import transaction
from django.shortcuts import render

# Create your views here.
from django_celery_beat.models import CrontabSchedule, PeriodicTask
from dvadmin_celery.views.task import CronSlpit, CeleryCrontabScheduleSerializer, PeriodicTasksSerializer
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated

from apitest.models import EnvInfo, ProjectInfo, ModuleInfo, TestApiInfo, TestApiResult, TestCase
from apitest.serializers import EnvInfoSerializer, ProjectInfoSerializer, ModuleInfoSerializer, TestApiInfoSerializer, \
    TestApiResultSerializer, TestCaseSerializer, ExportTestApiInfoSerializer, TestApiInfoImportSerializer
from dvadmin.utils.RequestUtil import RequestUtil
from dvadmin.utils.json_response import DetailResponse, ErrorResponse, SuccessResponse
from dvadmin.utils.string_util import load_json
from dvadmin.utils.viewset import CustomModelViewSet


class EnvInfoView(CustomModelViewSet):
    queryset = EnvInfo.objects.all()
    serializer_class = EnvInfoSerializer

    # search_fields = ['name', 'code']
    # ordering = ['-id']
    # ordering_fields = ['id', 'name', 'code']
    # filterset_fields = ['env_name', 'paramsbody']

    # http://127.0.0.1:8000/api/envinfo/switch_task/1/
    @action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated])
    @transaction.atomic
    def switch_task(self, request, pk):
        try:
            env = EnvInfo.objects.get(id=pk)
            env.default = not env.default
            env.save()
            # 当前改成true 其他数据改成false
            default = request.data.get('default', False)
            if default == True:
                EnvInfo.objects.exclude(id=pk).update(default=False)
            return DetailResponse(msg="切换成功")
        except Exception as e:
            return ErrorResponse(msg="切换失败")


class ProjectInfoView(CustomModelViewSet):
    queryset = ProjectInfo.objects.all()
    serializer_class = ProjectInfoSerializer


class ModuleInfoView(CustomModelViewSet):
    queryset = ModuleInfo.objects.all()
    serializer_class = ModuleInfoSerializer


class TestApiInfoView(CustomModelViewSet):
    queryset = TestApiInfo.objects.all()
    serializer_class = TestApiInfoSerializer
    search_fields = ["name"]  # 模糊搜索
    # 导出
    export_field_label = {
        "name": "测试用例",
        'method_name': '接口类型',
        "url": "请求地址",
        'create_datetime': '创建时间',
        'headers': '头部信息',
        'params': 'body参数',
        'jsonbody': 'json参数',
        'project_name': '所属项目',
        'module_name': '所属模块'
    }
    export_serializer_class = ExportTestApiInfoSerializer

    # 导入
    import_serializer_class = TestApiInfoImportSerializer
    import_field_dict = {
        "name": "测试用例",
        "url": "请求地址",
        "method": {
            "title": "协议类型",
            "choices": {
                "data": {"GET": 0, "POST": 1, "PUT": 2, 'DELETED': 3},
            }
        },
        "headers": "头部信息(json)",
        "params": "params类型字段(kv)",
        "jsonbody": "json类型字段(json)",
        "verification": "检查点",
        'extract': '关联字段',
        "project_belong": {"title": "工程信息",
                           "choices": {"queryset": ProjectInfo.objects.all(), "values_name": "project_name"}},
        "module_belong": {"title": "模块信息",
                          "choices": {"queryset": ModuleInfo.objects.all(), "values_name": "module_name"}},
    }

    @action(methods=["POST"], detail=False, permission_classes=[IsAuthenticated])
    def apiTest(self, request):
        print(request.data)
        pk = request.data.get('id')
        request_data = TestApiInfo.objects.get(id=pk)
        api = RequestUtil()
        evnditct = request.data.get('env')
        print(evnditct)
        if evnditct is not None:
            api.var_pool_data = json.loads(evnditct.get('paramsbody'))
        if request_data.get_method_display() == 'GET':
            api.send_request(request_data.get_method_display(), url=request_data.url,
                             headers=load_json(request_data.headers),
                             verification=request_data.verification)
        elif request_data.params is not None and request_data.params != "":
            params_dict = {}
            params = request_data.params.split("&")
            for p in params:
                ps = p.split("=")
                params_dict[ps[0]] = ps[1]
            api.send_request(request_data.get_method_display(), url=request_data.url,
                             headers=load_json(request_data.headers),
                             data=params_dict, verification=request_data.verification)
        else:
            api.send_request(request_data.get_method_display(), url=request_data.url,
                             headers=load_json(request_data.headers),
                             json=load_json(request_data.jsonbody), verification=request_data.verification)
        print(api.get_result())
        result_data = api.get_result()
        testresult = TestApiResult()
        testresult.api_belong = request_data
        testresult.project_belong = request_data.project_belong
        testresult.module_belong = request_data.module_belong
        testresult.env_belong = EnvInfo.objects.get(id=evnditct.get('id'))
        testresult.took_time = result_data.get('took_time')
        testresult.verification = result_data.get('check_result')
        testresult.result = result_data.get('response')[:200]
        testresult.save()
        if result_data.get('code') == 0:
            return ErrorResponse(msg="测试失败")
        return DetailResponse(msg="测试成功")


class TestApiResultView(CustomModelViewSet):
    queryset = TestApiResult.objects.all()
    serializer_class = TestApiResultSerializer

    @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
    def count(self, request):
        env = request.query_params.get('env')
        if env:
            result_list = self.get_queryset().filter(env_belong=env).values()
        else:
            result_list = self.get_queryset().values()
        result_dic = {}
        # 总接口数目
        allapis = TestApiInfo.objects.all().count()
        # 已经测过接口
        testapis = result_list.values('api_belong').distinct().count()
        # 接口完成率
        finshed = round(testapis / allapis * 100, 2)
        result_dic['allApis']  = '0' if allapis == 0 else allapis
        result_dic['testApis'] = '0' if testapis == 0 else testapis
        result_dic['total'] = '0' if len(result_list) == 0 else len(result_list)
        # 饼图
        sucess_list = list(filter(lambda x: x.get('verification') == '检查成功', result_list))
        fail_list = list(filter(lambda x: x.get('verification') == '检查失败', result_list))
        skip_list = list(filter(lambda x: x.get('verification') == '没有设置检查点', result_list))
        pie = []
        pie.append({'value': len(sucess_list), 'name': '检查成功'}, )
        pie.append({'value': len(fail_list), 'name': '检查失败'}, )
        pie.append({'value': len(skip_list), 'name': '跳过检查'}, )
        result_dic['apicount'] = pie
        # 仪表盘
        result_dic['finshed'] = finshed
        return DetailResponse(data=result_dic, msg="测试成功")


class TestCaseView(CustomModelViewSet):
    queryset = TestCase.objects.all()
    serializer_class = TestCaseSerializer

    @action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated])
    def case_test(self, request, pk):
        print(request.data)
        case = TestCase.objects.get(id=pk)
        apis = case.apis.all()
        api = RequestUtil()
        evnditct = request.data.get('env')
        print(evnditct)
        if evnditct is not None:
            api.var_pool_data = json.loads(evnditct.get('paramsbody'))
        for request_data in apis:
            if request_data.get_method_display() == 'GET':
                api.send_request(request_data.get_method_display(), url=request_data.url,
                                 headers=load_json(request_data.headers),
                                 verification=request_data.verification, extract=request_data.extract)
            elif request_data.params is not None and request_data.params != "":
                params_dict = {}
                params = request_data.params.split("&")
                for p in params:
                    ps = p.split("=")
                    params_dict[ps[0]] = ps[1]
                api.send_request(request_data.get_method_display(), url=request_data.url,
                                 headers=load_json(request_data.headers),
                                 data=params_dict, verification=request_data.verification, extract=request_data.extract)
            else:
                api.send_request(request_data.get_method_display(), url=request_data.url,
                                 headers=load_json(request_data.headers),
                                 json=load_json(request_data.jsonbody), verification=request_data.verification,
                                 extract=request_data.extract)
            print(api.get_result())
            result_data = api.get_result()
            testresult = TestApiResult()
            testresult.api_belong = request_data
            testresult.case_belong = case
            testresult.project_belong = request_data.project_belong
            testresult.module_belong = request_data.module_belong
            testresult.env_belong = EnvInfo.objects.get(id=evnditct.get('id'))
            testresult.took_time = result_data.get('took_time')
            testresult.verification = result_data.get('check_result')
            testresult.result = result_data.get('response')[:200]
            testresult.save()
        # request_data = load_json(case.request_data)
        return DetailResponse(msg="测试成功")

    @transaction.atomic
    def create(self, request, *args, **kwargs):
        serializer_case = self.get_serializer(data=request.data, request=request)
        serializer_case.is_valid(raise_exception=True)
        case_obj = serializer_case.save()
        case = serializer_case.data
        cron = request.data.get('cron')
        if cron is not None and cron != '':
            cron_data = CronSlpit(cron)
            # 添加crontab
            serializer = CeleryCrontabScheduleSerializer(data=cron_data)
            serializer.is_valid(raise_exception=True)
            print(cron_data)
            schedule, created = CrontabSchedule.objects.get_or_create(**cron_data)  # 手动创建crontab，避免重复创建
            # PeriodicTasks
            body_data = {}
            print(schedule.id)
            body_data['name'] = case.get('case_name')
            body_data['crontab'] = schedule.id
            body_data['enabled'] = True
            body_data['task'] = 'apitest.tasks.task__api'
            env = request.data.get('env')
            env_id = env.get('id')
            body_data['kwargs'] = json.dumps({'case_id': case.get('id'), 'env_id': env_id})
            serializer = PeriodicTasksSerializer(data=body_data)
            serializer.is_valid(raise_exception=True)
            periodic_task = serializer.save()
            case_obj.task_belong = periodic_task
            case_obj.save()
        return DetailResponse(data=serializer_case.data, msg="新增成功")

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        periodic_task = instance.task_belong
        if periodic_task is not None:
            periodic_task.delete()
        instance.delete()
        return DetailResponse(data=[], msg="删除成功")

    @action(methods=['delete'], detail=False)
    def multiple_delete(self, request, *args, **kwargs):
        request_data = request.data
        keys = request_data.get('keys', None)
        if keys:
            task_list = self.get_queryset().filter(id__in=keys).filter(task_belong__isnull=False)
            for task in task_list:
                task.task_belong.delete()
            self.get_queryset().filter(id__in=keys).delete()
            return SuccessResponse(data=[], msg="删除成功")
        else:
            return ErrorResponse(msg="未获取到keys字段")

    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, request=request, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        # 新增
        cron = request.data.get('cron')
        task_belong = instance.task_belong
        if task_belong is None and cron is not None and cron != '':
            cron_data = CronSlpit(cron)
            # 添加crontab
            serializer = CeleryCrontabScheduleSerializer(data=cron_data)
            serializer.is_valid(raise_exception=True)
            print(cron_data)
            schedule, created = CrontabSchedule.objects.get_or_create(**cron_data)  # 手动创建crontab，避免重复创建
            # PeriodicTasks
            body_data = {}
            print(schedule.id)
            body_data['name'] = instance.case_name
            body_data['crontab'] = schedule.id
            body_data['enabled'] = True
            body_data['task'] = 'apitest.tasks.task__api'
            env = request.data.get('env')
            env_id = env.get('id')
            body_data['kwargs'] = json.dumps({'case_id': instance.id, 'env_id': env_id})
            serializer = PeriodicTasksSerializer(data=body_data)
            serializer.is_valid(raise_exception=True)
            periodic_task = serializer.save()
            instance.task_belong = periodic_task
            instance.save()
        # 修改
        if task_belong is not None and cron is not None and cron != '':
            dbcron = instance.task_belong.crontab.__str__()
            cron_data = f'{cron}{instance.task_belong.crontab.timezone}'
            if cron_data != dbcron:
                cron_data = CronSlpit(cron)
                schedule, created = CrontabSchedule.objects.get_or_create(**cron_data)
                task_belong.crontab = schedule
                task_belong.save()
        if task_belong is not None and cron is None:
            task_belong.delete()
            instance.task_belong = None
            instance.save()

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}
        return DetailResponse(data=serializer.data, msg="更新成功")
